
#include "KeyDeclear.h"
#include "CToken.h"
#include <iostream>
using namespace MyRegular_Token;
/*RAGEX_COMMON_DECLEAR( MACRO_CLASS_FUNC_TEST_DECLEAR )
RAGEX_SINGLE_DECLEAR( MACRO_CLASS_FUNC_TEST_DECLEAR )
REGEX_TO_DECLEAR( MACRO_CLASS_FUNC_TEST_DECLEAR )
REGEX_BOUND_DECLEAR( MACRO_CLASS_FUNC_TEST_DECLEAR )
REGEX_BACK_DECLEAR( MACRO_CLASS_FUNC_TEST_DECLEAR )
REGEX_AUXILIARY_DECLAR( MACRO_CLASS_FUNC_TEST_DECLEAR )

REGEX_END_DECLEAR( MACRO_CLASS_FUNC_TEST_DECLEAR_END )

RAGEX_COMMON_DECLEAR( MACRO_CLASS_FUNC_MERGE_DECLEAR )
RAGEX_SINGLE_DECLEAR( MACRO_CLASS_FUNC_MERGE_DECLEAR )
REGEX_TO_DECLEAR( MACRO_CLASS_FUNC_MERGE_DECLEAR )
REGEX_BOUND_DECLEAR( MACRO_CLASS_FUNC_MERGE_DECLEAR )
REGEX_END_DECLEAR( MACRO_CLASS_FUNC_MERGE_DECLEAR )
REGEX_BACK_DECLEAR( MACRO_CLASS_FUNC_MERGE_DECLEAR )
REGEX_AUXILIARY_DECLAR( MACRO_CLASS_FUNC_MERGE_DECLEAR )
*/
const char* MyRegular_Token::GetTokenDecl( ECTokenType et ){
#define MM( a, b, c, d, e, f, g, h )	\
	case a: return #a;	

#define CASECONSTRCT( a, b )			\
	case ECTT_##a: return b;

	switch( et ){
	RAGEX_SINGLE_DECLEAR( MM )
	REGEX_TO_DECLEAR( MM )
	REGEX_BOUND_DECLEAR( MM )
	REGEX_END_DECLEAR( MM )
	REGEX_BACK_DECLEAR( MM )
	REGEX_AUXILIARY_DECLAR( MM )
	TOKENLIST_DECL( CASECONSTRCT )
	}
	return "";
#undef MM
#undef CASECONSTRCT
}
bool CToken::IsControlSymbol( char c ){
#define M( a )		\
	#a
	static char* g_pstr = RAGEX_SINGLE_DECLEAR( M )REGEX_TO_DECLEAR( M )REGEX_BOUND_DECLEAR( M )REGEX_END_DECLEAR( M )REGEX_BACK_DECLEAR( M )REGEX_AUXILIARY_DECLAR( M );
	if( strchr( g_pstr, c ) )
		return true;
	return false;
#undef M
}
void CToken::GetString1(){
	m_strBuf = "";
	do 
	{
		m_strBuf += *m_itStr;
		if( ++m_itStr == m_strSource.end() )
			return;
		if( IsControlSymbol( *m_itStr ) )
			return;
	} while( 1 );
}
void CToken::GetString2(){
	do{
		if( m_itStr == m_strSource.end() )
			return;
		if( '\\' == *m_itStr ){
			string::iterator it = m_itStr++;
			int type = ConverFunc();
			if( type == ECTT_UShort ){
				int iret = GetConverValue();
				m_strBuf += ( char* )&iret;
			}
			else
			if( type < ECTT_StartMark )
				m_strBuf += ( char )type;			
			else{
				m_itStr = it;
				return;
			}
		}
		else
		if( IsControlSymbol( *m_itStr ) ){
			return;
		}
		else{
			m_strBuf += *m_itStr++;
		}
	}while( 1 );
}
int CToken::GetNextToken(){
	ECTokenType ett;
	if( m_itStr == m_strSource.end() ){
		return m_ett =  ECTT_END;
	}
	if( '\\' == *m_itStr ){
		string::iterator it = m_itStr++;
		int type = ConverFunc();
		if( type < 0 )
			return  m_ett = ECTT_END;
		if( type == ECTT_UShort ){
			int iret = GetConverValue();
			m_strBuf = ( char* )&iret;
			GetString2();
			return m_ett = ECTT_String;
		}
		if( type < ECTT_StartMark ){
			m_strBuf = ( char )type;
			GetString2();
			return m_ett =  ECTT_String;
		}
		return m_ett =  ( ECTokenType )type;
	}
	if( !IsControlSymbol( *m_itStr ) ){
		m_strBuf = "";
		GetString2();
		return m_ett =  ECTT_String;
	}
	return m_ett = ( ECTokenType )*m_itStr++;
}
bool CToken::StringTopCheck( char c ){
	if( IsControlSymbol( c ) )
		return false;
	return true;
}
int CToken::TestHexChar( char c ){
	if( ( c >= 'a' && c <= 'z' ) )
		return c - 'a';
	if( c >= 'A' && c <= 'Z' ) 
		return c - 'A';
	if( c >= '0' && c <= '9' )
		return c - '0';
	return -1;
}
int CToken::ConverFunc(){
#define _TESTEND	if( m_itStr == m_strSource.end() ) return -1;
	int iRet, iTmp;
	_TESTEND
	switch( *m_itStr++ ){
	case 'b': return ECTT_TestB;
	case 'B': return ECTT_TestE;
	case 'd': return ECTT_Number;
	case 'D': return ECTT_NNumber;
	case 'f': return 0x0c;
	case 'n': return 0x0a;
	case 'r': return 0x0d;
	case 's': return ECTT_Space;
	case 'S': return ECTT_NSpace;
	case 't': return 0x09;
	case 'v': return 0x0b;
	case 'w': return ECTT_Name;
	case 'W': return ECTT_NName;
	case 'c': 
		_TESTEND
		if( !isalpha( *m_itStr ) )
			return 'c';
		iConverValue = *m_itStr++;
		return ECTT_ControlCode;
	case 'x':
		_TESTEND
		if( -1 == ( iTmp = TestHexChar( *m_itStr++ ) ) )
			return -2;
		iRet = iTmp;
		
		if( -1 == ( iTmp = TestHexChar( *m_itStr++ ) ) )
			return iRet;
		return ( iRet << 4 ) | iTmp;
	case 'u':
		iTmp = 0;
		iConverValue = 0;
		do{
			_TESTEND
			if( -1 == ( iRet = TestHexChar( *m_itStr++ ) ) )
				return -3;
			iConverValue = ( iConverValue << 4 ) | iRet;
		}while( ++iTmp < 4 );
		return ECTT_UShort;
	default:
		_TESTEND
		if( !isdigit( *m_itStr ) )
			return *m_itStr++;
		iConverValue = *m_itStr++ - '0';
		return ECTT_RecordNumber;
	}
	return -4;
#undef _TESTEND
}
int CToken::GetNextOriginalChar(){
	if( ++m_itStr == m_strSource.end() )
		return -1;
	return *m_itStr;
}
void CTestToken::Test( const char* pszSource ){
	CToken token;
	token.InitTokenEnv( pszSource );
	int iToken;
	while( ECTT_END != ( iToken = token.GetNextToken() ) ){
		cout << "Token: " << GetTokenDecl( ( ECTokenType )iToken ) << endl;
		if( iToken == ECTT_String )
			cout << "\t" << token.GetTokenString() << endl;
	}
}